#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "globals.h"

struct cmd_node *if_item, *goto_item;

void cmd_node_add(struct cmd_node **list, int opcode, int param1, int param2) {
	struct cmd_node *iter = *list;
	
	if (*list == NULL) {
		*list = malloc(sizeof(struct cmd_node));
		(*list)->opcode = opcode;
		(*list)->param1 = param1;
		(*list)->param2 = param2;
		(*list)->byte_position = 0;
		(*list)->next = NULL;
	} else {
		while (iter && iter->next != NULL) {
			iter = iter->next;
		}

		iter->next = malloc(sizeof(struct cmd_node));
		iter->next->byte_position = iter->byte_position + 1;
		iter = iter->next;
		iter->opcode = opcode;
		iter->byte_position = current_byte;
		iter->param1 = param1;
		iter->param2 = param2;
	}

	/*
	 * Se esta iniciando um bloco "SE ENTAO" guarga ponteiro para 
	 * fazer retro alteracao quando encontrar marca
	 */
	if (opcode == IF_ICMPGT || opcode == IF_ICMPEQ) {
		// bloco true vai ser sempre igual current_byte + 3
		iter->param1 = current_byte + 3;
		if_item = iter;
	}
	
	/*
	 * SE ACHAR GOTO GUARDA REFERENCIA
	 */
	if (opcode == GOTO) {
		goto_item = iter;
	}
	
	/*
	 * Se encontrou marca LABEL_BRANCH_WHEN_FALSE entao altera branch
	 * da condicao falsa em if_item
	 */
	if (opcode == LABEL_BRANCH_WHEN_FALSE) {
		if (if_item != NULL) {
			if_item->param2 = current_byte;
			if_item = NULL;
		}

		if (goto_item != NULL) {
			goto_item->param1 = current_byte;
		}
	}
	
	// bytecodes com que usam 1 byte
	if (opcode == IADD || opcode == ISUB || opcode == IDIV || opcode == IMUL) {
		current_byte += 1;
	}

	// bytecodes com que usam 2 byte
	else if (opcode == BIPUSH || opcode == ISTORE || opcode == ILOAD) {
		current_byte += 2;
	}

	else if (opcode == IF_ICMPGT || opcode == IF_ICMPEQ || opcode == GOTO) {
		current_byte += 3;
	}
}

void cmd_node_dump(struct cmd_node **list) {
	struct cmd_node *iter = *list;

	#ifdef DEBUG
	while (iter) {
		printf("opcode=%d  ---  param1=%d  ---  param2=%d\n", iter->opcode, iter->param1, iter->param2);
		iter = iter->next;
	}
	#endif
}


void cmd_node_to_source(struct cmd_node **list) {
	struct cmd_node *iter = *list;


	while (iter) {
		#ifdef DEBUG
			printf("%d:\t", iter->byte_position);
		#endif

		if (iter->opcode == IMUL) {
			#ifdef DEBUG 
				printf("<imul>\n");
			#else
				printf("%d", IMUL);
			#endif

		} else if (iter->opcode == IADD) {
			#ifdef DEBUG 
				printf("<iadd>\n");
			#else
				printf("%d\n", IADD);
			#endif

		} else if (iter->opcode == ISUB) {
			#ifdef DEBUG 
				printf("<isub>\n");
			#else
				printf("%d\n", ISUB);
			#endif

		} else if (iter->opcode == IDIV) {
			#ifdef DEBUG 
				printf("<idiv>\n");
			#else
				printf("%d\n", IDIV);
			#endif

		} else if (iter->opcode == BIPUSH) {
			#ifdef DEBUG 
				printf("<bipush %d>\n", iter->param1);
			#else
				printf("%d\n", BIPUSH);
				printf("%d\n", iter->param1);
			#endif

		} else if (iter->opcode == ISTORE) {
			#ifdef DEBUG 
				printf("<istore_%d>\n", iter->param1);
			#else
				printf("%d\n", ISTORE);
				printf("%d\n", iter->param1);
			#endif

		} else if (iter->opcode == ILOAD) {
			#ifdef DEBUG 
				printf("<iload_%d>\n", iter->param1);
			#else
				printf("%d\n", ILOAD);
				printf("%d\n", iter->param1);
			#endif

		} else if (iter->opcode == IF_ICMPGT) {
			#ifdef DEBUG 
				printf("<if_icmpgt tt=(%d) ff=(%d)>\n", iter->param1, iter->param2);
			#else
				printf("%d\n", IF_ICMPGT);
				printf("%d\n", iter->param1);
				printf("%d\n", iter->param2);
			#endif

		} else if (iter->opcode == IF_ICMPEQ) {
			#ifdef DEBUG 
				printf("<if_icmpeq tt=(%d) ff=(%d)>\n", iter->param1, iter->param2);
			#else
				printf("%d\n", IF_ICMPEQ);
				printf("%d\n", iter->param1);
				printf("%d\n", iter->param2);
			#endif

		} else if (iter->opcode == LABEL_BRANCH_WHEN_FALSE) {
			#ifdef DEBUG 
				//printf("<label_end_if>\n");
			#endif
		
		} else if (iter->opcode == LABEL_END_BLOCK) {
			#ifdef DEBUG 
				//printf("<label_end_block>\n");
			#endif
		
		} else if (iter->opcode == GOTO) {
			#ifdef DEBUG 
				printf("<goto %d>\n", iter->param1);
			#else
			#endif
		}

		iter = iter->next;
		#ifdef DEBUG
		printf("\n");
		#endif

	}
	
}
